package com.loser.excel.core.handler;

import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSONObject;
import com.loser.excel.constant.ExportStatusEnum;
import com.loser.excel.constant.IExcelExportTypes;
import com.loser.excel.core.ExcelExportParams;
import com.loser.excel.core.ExcelExportType;
import com.loser.excel.core.handler.listener.ExportExcelEventListener;
import com.loser.excel.model.ExportTaskInfo;
import com.loser.redis.core.RedisHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.Collection;
import java.util.Objects;

/**
 * @author alan
 */
public class ExcelExportHandler implements ApplicationListener<ContextRefreshedEvent> {

    private static final Logger log = LoggerFactory.getLogger(ExcelExportHandler.class);

    private final RedisHandler redisHandler;

    private Collection<ExportExcelEventListener> exportExcelEventListeners;

    public ExcelExportHandler(RedisHandler redisHandler) {
        this.redisHandler = redisHandler;
    }

    /**
     * 初始化一个工单并保存
     */
    public void initTaskInfoAndSave(Long taskId, String exportUser, ExcelExportParams<?, ?> queryParams, ExcelExportType excelExportType, String fileName) {

        ExportTaskInfo taskInfo = new ExportTaskInfo();
        taskInfo.setId(taskId);
        taskInfo.setFileName(fileName);
        taskInfo.setUserId(exportUser);
        taskInfo.setStatus(ExportStatusEnum.LOADING.getStatus());
        taskInfo.setCreateTime(System.currentTimeMillis());
        taskInfo.setSearchCondition(queryParams);
        taskInfo.setExportCategory(excelExportType.getCategory());
        redisHandler.set(String.format(IExcelExportTypes.TASK_INFO, taskId), JSONObject.toJSONString(taskInfo), 86400000L);

        for (ExportExcelEventListener listener : exportExcelEventListeners) {
            try {
                listener.initEvent(taskInfo);
            } catch (Exception e) {
                log.error("handler initEvent throw a e data {}", JSONObject.toJSONString(taskInfo), e);
            }
        }

    }

    /**
     * 更新任务状态
     *
     * @param status 任务状态 工单状态, ExportStatusEnum
     */
    public void updateTaskStatus(Long taskId, String status, Exception e) {

        String result = redisHandler.get(String.format(IExcelExportTypes.TASK_INFO, taskId));
        ExportTaskInfo taskInfo = JSONObject.parseObject(result, ExportTaskInfo.class);
        taskInfo.setId(taskId);
        taskInfo.setStatus(status);
        taskInfo.setUpdateTime(System.currentTimeMillis());
        redisHandler.set(String.format(IExcelExportTypes.TASK_INFO, taskId), JSONObject.toJSONString(taskInfo), 86400000L);

        for (ExportExcelEventListener listener : exportExcelEventListeners) {
            try {
                if (Objects.equals(status, ExportStatusEnum.DELETED.getStatus())) {
                    listener.deletedEvent(taskInfo);
                } else if (Objects.equals(status, ExportStatusEnum.FAILURE.getStatus())) {
                    listener.failureEvent(taskInfo, e);
                } else if (Objects.equals(status, ExportStatusEnum.USER_STOP.getStatus())) {
                    listener.stopEvent(taskInfo);
                }
            } catch (Exception exception) {
                log.error("handler event throw a e data {}", JSONObject.toJSONString(taskInfo), exception);
            }
        }

    }

    public static String getExceptionAllInfo(Exception ex) {

        ByteArrayOutputStream out;
        PrintStream pout = null;
        String ret;
        try {
            out = new ByteArrayOutputStream();
            pout = new PrintStream(out);
            ex.printStackTrace(pout);
            ret = out.toString();
            out.close();
        } catch (Exception e) {
            return ex.getMessage();
        } finally {
            if (pout != null) {
                pout.close();
            }
        }
        return ret;
    }

    /**
     * 更新任务的文件下载地址
     */
    public void updateTaskPath(Long taskId, String path) {


        String result = redisHandler.get(String.format(IExcelExportTypes.TASK_INFO, taskId));
        ExportTaskInfo taskInfo = JSONObject.parseObject(result, ExportTaskInfo.class);
        taskInfo.setId(taskId);
        taskInfo.setFilePath(path);
        taskInfo.setUpdateTime(System.currentTimeMillis());
        taskInfo.setStatus(ExportStatusEnum.FINISH.getStatus());
        redisHandler.set(String.format(IExcelExportTypes.TASK_INFO, taskId), JSONObject.toJSONString(taskInfo), 86400000L);

        for (ExportExcelEventListener listener : exportExcelEventListeners) {
            try {
                listener.finishEvent(taskInfo);
            } catch (Exception e) {
                log.error("handler finishEvent throw a e data {}", JSONObject.toJSONString(taskInfo), e);
            }
        }

    }


    /**
     * 设置导出任务的进度
     */
    private void setTaskProgress(ExcelExportRecordView view) {

        if (view.getStatus() == 1) {
            try {
                JSONObject object = JSONObject.parseObject(view.getParams(), JSONObject.class);
                int exportCount = object.getIntValue("exportCount");
                view.setTotalCount(exportCount);
                Object redisCount = redisHandler.hget(IExcelExportTypes.DOING_EXPORT_KEY, view.getId());
                if (Objects.isNull(redisCount)) {
                    redisCount = "0";
                }
                Integer finishCount = Convert.toInt(redisCount);
                // 避免上传过程中进度条已经走完
                if (finishCount >= exportCount) {
                    finishCount = Convert.toInt(exportCount * 0.9999);
                }
                view.setFinishCount(finishCount);
                view.setShowProgressBar(true);
            } catch (Exception e) {
                log.warn("setTaskProgress Exception:{}", view, e);
                view.setShowProgressBar(false);
                view.setTotalCount(1);
                view.setFinishCount(1);
            }
        } else {
            view.setShowProgressBar(false);
            view.setTotalCount(1);
            view.setFinishCount(1);
        }

    }

    /**
     * 中断任务
     * 提供标志为给切面做判断
     */
    public Boolean stopTask(Long taskId) {

        String key = String.format(IExcelExportTypes.STOP_EXPORT_KEY, taskId);
        redisHandler.set(key, Convert.toStr(taskId), 1000L);
        updateTaskStatus(taskId, ExportStatusEnum.USER_STOP.getStatus(), null);
        return true;

    }


    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        exportExcelEventListeners = contextRefreshedEvent.getApplicationContext().getBeansOfType(ExportExcelEventListener.class).values();
    }
}
